#include "common_shell.h"
#include <iostream>
#include <sstream>
#include <algorithm>
#include <linenoise.h>
#include "base_log.h"
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <cstring>
#include <cstdlib>
#include <sys/reboot.h>
#include "common_event.h"

namespace El {
namespace Common {

std::vector<std::string> Shell::s_command_names;

Shell &Shell::GetInstance()
{
    static Shell instance;
    return instance;
}

Shell::Shell() : m_running(false)
{
    RegisterDefaultCommands();
}

Shell::~Shell()
{
    Stop();
}

void Shell::RegisterCommand(const std::string &name, CommandFunction command)
{
    std::lock_guard<std::mutex> lock(m_mutex);
    m_commands[name] = std::move(command);
    s_command_names.push_back(name);
}

void Shell::RegisterDefaultCommands()
{
    RegisterCommand("help", [this](const std::string &args) {
        (void)args;
        std::lock_guard<std::mutex> lock(m_mutex);
        std::cout << "Available commands:\n";
        for (const auto &name : s_command_names) {
            std::cout << "  " << name << "\n";
        }
    });

    RegisterCommand("quit", [this](const std::string &args) {
        (void)args;
        Event::GetInstance().Notify("quit", "");

        LOG_INFO("_exit");
        _exit(0);
    });

    RegisterCommand("shell", [](const std::string &args) {
        (void)args;
        LOG_INFO("Opening /bin/sh...");
        int result = system("/bin/sh");
        if (result == -1) {
            LOG_ERROR("Failed to execute /bin/sh: {}", strerror(errno));
        } else if (WIFEXITED(result)) {
            LOG_INFO("Shell session ended with exit status: {}", WEXITSTATUS(result));
        } else {
            LOG_INFO("Shell session ended abnormally");
        }
    });

    RegisterCommand("log", [](const std::string &args) {
        std::istringstream iss(args);
        std::string level;
        iss >> level;

        // 转换为小写以便进行比较
        std::transform(level.begin(), level.end(), level.begin(), ::tolower);

        if (level.empty()) {
            LOG_INFO("Current log levels: trace, debug, info, warn, error, critical, off");
            LOG_INFO("Usage: log <level>");
            return;
        }

        Base::Log::GetInstance().setLogLevel(level);
    });

    RegisterCommand("reboot", [](const std::string &args) {
        (void)args;
        LOG_INFO("Rebooting the system...");
        sync(); // 同步文件系统缓冲区
        if (reboot(RB_AUTOBOOT) == -1) {
            LOG_ERROR("Failed to reboot: {}", strerror(errno));
        }
        // 如果reboot成功,这里的代码不会被执行
    });

    // 可以在这里添加更多默认命令
}

void Shell::Start()
{
    std::lock_guard<std::mutex> lock(m_mutex);
    if (!m_running) {
        m_running = true;
        m_thread = std::thread(&Shell::RunShell, this);
    }
}

void Shell::Stop()
{
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_running) {
        m_running = false;
        if (m_thread.joinable()) {
            m_thread.join();
        }
    }
}

char *Shell::CommandGenerator(const char *text, int state)
{
    static std::vector<std::string>::iterator it;
    if (state == 0)
        it = s_command_names.begin();
    while (it != s_command_names.end()) {
        const std::string &name = *it++;
        if (name.compare(0, strlen(text), text) == 0) {
            return strdup(name.c_str());
        }
    }
    return nullptr;
}

char **Shell::CommandCompletion(const char *text, int start, int end)
{
    (void)text;
    (void)start;
    (void)end;
    // linenoise does not support custom completion functions directly like readline
    return nullptr;
}

void Shell::ProcessCommand(const std::string &input)
{
    std::istringstream iss(input);
    std::string command;
    iss >> command;

    auto it = m_commands.find(command);
    if (it != m_commands.end()) {
        std::string args;
        std::getline(iss >> std::ws, args);
        it->second(args);
    } else {
        LOG_ERROR("Unknown command: {}", command);
    }
}

void Shell::RunShell()
{
    while (m_running) {
        char *line = linenoise("myshell> ");
        if (line == nullptr) {
            LOG_INFO("Exiting...");
            break;
        }

        std::string input(line);
        if (!input.empty()) {
            linenoiseHistoryAdd(line);
            ProcessCommand(input);
        }
        free(line);
    }
}

} // namespace Common
} // namespace El